import { PROPS_ENUM, ENUM_SHOW_SPLITOR } from './../Runtime/Global/variable';
import { getServiceInfoByIds } from '@CIF/API/api.js';
import { pwdDecrypt } from '@/utils/encryption/pwd.ts';
import pako from 'pako';

/**
 * 判断是否为空, 要注意此方法内部会调用 deepClone 作深拷贝操作，因此传入的对象不要存在循环引用的情况！否则会爆栈
 */
export function validatenull(val) {
	// 特殊判断
	if (val && parseInt(val) === 0) return false;
	const list = ['$parent'];
	if (val instanceof Date || typeof val === 'boolean' || typeof val === 'number') return false;
	if (val instanceof Array) {
		if (val.length === 0) return true;
	} else if (val instanceof Object) {
		val = deepClone(val);
		list.forEach((ele) => {
			delete val[ele];
		});
		for (let o in val) {
			return false;
		}
		return true;
	} else {
		if (val === 'null' || val == null || val === 'undefined' || val === undefined || val === '') {
			return true;
		}
		return false;
	}
	return false;
}

export function getFixed(val = 0, len = 2) {
	return Number(val.toFixed(len));
}
export function getAsVal(obj, bind = '') {
	let result = deepClone(obj);
	if (validatenull(bind)) return result;
	bind.split('.').forEach((ele) => {
		result = !validatenull(result[ele]) ? result[ele] : '';
	});
	return result;
}

export function setAsVal(obj, bind = '', value = '') {
	eval('obj.' + bind + '=`' + value + '`');
	return obj;
}
export const loadScript = (type = 'js', url) => {
	let flag = false;
	return new Promise((resolve) => {
		const head = document.getElementsByTagName('head')[0];
		head.children.forEach((ele) => {
			if ((ele.src || '').indexOf(url) !== -1) {
				flag = true;
				resolve();
			}
		});
		if (flag) return;
		let script;
		if (type === 'js') {
			script = document.createElement('script');
			script.type = 'text/javascript';
			script.src = url;
		} else if (type === 'css') {
			script = document.createElement('link');
			script.rel = 'stylesheet';
			script.type = 'text/css';
			script.href = url;
		}
		head.appendChild(script);
		script.onload = function () {
			resolve();
		};
	});
};
export function downFile(url, saveName) {
	if (typeof url == 'object' && url instanceof Blob) {
		url = URL.createObjectURL(url); // 创建blob地址
	}
	const aLink = document.createElement('a');
	aLink.href = url;
	aLink.download = saveName || ''; // HTML5新增的属性，指定保存文件名，可以不要后缀，注意，file:///模式下不会生效
	let event;
	if (window.MouseEvent) {
		event = new MouseEvent('click');
	} else {
		event = document.createEvent('MouseEvents');
		event.initMouseEvent(
			'click',
			true,
			false,
			window,
			0,
			0,
			0,
			0,
			0,
			false,
			false,
			false,
			false,
			0,
			null
		);
	}
	aLink.dispatchEvent(event);
}
export function strCorNum(list) {
	list.forEach((ele, index) => {
		list[index] = Number(ele);
	});
	return list;
}
export function extend() {
	let target = arguments[0] || {};
	let deep = false;
	let arr = Array.prototype.slice.call(arguments);
	let i = 1;
	let options, src, key, copy;
	let isArray = false;
	if (typeof target === 'boolean') {
		deep = target;
		i++;
		target = arguments[1];
	}
	for (; i < arr.length; i++) {
		// 循环传入的对象数组
		if ((options = arr[i]) != null) {
			// 如果当前值不是null，如果是null不做处理
			for (key in options) {
				// for in循环对象中key
				copy = options[key];
				src = target[key];
				// 如果对象中value值任然是一个引用类型
				if (
					deep &&
					(toString.call(copy) === '[object Object]' ||
						(isArray = toString.call(copy) == '[object Array]'))
				) {
					if (isArray) {
						// 如果引用类型是数组
						// 如果目标对象target存在当前key，且数据类型是数组，那就还原此值，如果不是就定义成一个空数组;
						src = toString.call(src) === '[object Array]' ? src : [];
					} else {
						// 如果目标对象target存在当前key，且数据类型是对象，那就还原此值，如果不是就定义成一个空对象;
						src = toString.call(src) === '[object Object]' ? src : {};
					}
					// 引用类型就再次调用extend，递归，直到此时copy是一个基本类型的值。
					target[key] = extend(deep, src, copy);
				} else if (copy !== undefined && copy !== src) {
					// 如果这个值是基本值类型，且不是undefined
					target[key] = copy;
				}
			}
		}
	}
	return target;
}
export function createObj(obj, bind) {
	let list = bind.split('.');
	let first = list.splice(0, 1)[0];
	let deep = {};
	deep[first] = {};
	if (list.length >= 2) {
		let start = '{';
		let end = '}';
		let result = '';
		list.forEach((ele) => {
			result = `${result}${start}"${ele}":`;
		});
		result = `${result}""`;
		for (let i = 0; i < list.length; i++) {
			result = `${result}${end}`;
		}
		result = JSON.parse(result);
		deep[first] = result;
	}
	obj = extend(true, obj, deep);
	return obj;
}
export function dataURLtoFile(dataurl, filename) {
	let arr = dataurl.split(',');
	let mime = arr[0].match(/:(.*?);/)[1];
	let bstr = atob(arr[1]);
	let n = bstr.length;
	let u8arr = new Uint8Array(n);
	while (n--) {
		u8arr[n] = bstr.charCodeAt(n);
	}
	return new File([u8arr], filename, {
		type: mime
	});
}

export function findObject(list, value, key = 'prop') {
	let result = -1;
	let type = (() => {
		let result;
		list.forEach((ele) => {
			if (ele.column) {
				result = 'group';
			} else if (ele.children) {
				result = 'tree';
			}
		});
		return result;
	})();
	if (type === 'group') {
		list.forEach((ele) => {
			const val = findArray(ele.column, value, key, true);
			if (val !== -1) result = val;
		});
	} else if (type === 'tree') {
		result = findLabelNode(list, value, { value: key }, true);
	} else {
		result = findArray(list, value, key, true);
	}
	return result;
}
/**
 * 生成随机数
 */
export function randomId() {
	let $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
	let maxPos = $chars.length;
	let id = '';
	for (let i = 0; i < 16; i++) {
		id += $chars.charAt(Math.floor(Math.random() * maxPos));
	}
	return id;
}
export const getObjType = (obj) => {
	let toString = Object.prototype.toString;
	let map = {
		'[object Boolean]': 'boolean',
		'[object Number]': 'number',
		'[object String]': 'string',
		'[object Function]': 'function',
		'[object Array]': 'array',
		'[object Date]': 'date',
		'[object RegExp]': 'regExp',
		'[object Undefined]': 'undefined',
		'[object Null]': 'null',
		'[object Object]': 'object'
	};
	if (obj instanceof Element) {
		return 'element';
	}
	return map[toString.call(obj)];
};
/**
 *判断是否为json对象
 */

export const isJson = (str) => {
	if (Array.isArray(str)) {
		if (str[0] instanceof Object) {
			return true;
		} else {
			return false;
		}
	} else if (str instanceof Object) {
		return true;
	}
	return false;
};

/**
 * 对象深拷贝
 * @param {*} data
 * @returns
 */
export const deepClone = (data) => {
	let type = getObjType(data);
	let obj;
	if (type === 'array') obj = [];
	else if (type === 'object') obj = {};
	else return data;
	if (type === 'array') {
		for (let i = 0, len = data.length; i < len; i++) {
			data[i] = (() => {
				if (data[i] === 0) {
					return data[i];
				}
				return data[i];
			})();
			if (data[i]) {
				delete data[i].$parent;
			}
			obj.push(deepClone(data[i]));
		}
	} else if (type === 'object') {
		for (let key in data) {
			if (data) {
				delete data.$parent;
			}
			obj[key] = deepClone(data[key]);
		}
	}
	return obj;
};
/**
 * 根据字段数组排序
 */
export const sortArrys = (list, prop) => {
	list.sort(function (a, b) {
		if (a[prop] > b[prop]) {
			return -1;
		}
		if (a[prop] < b[prop]) {
			return 1;
		}
		return 0;
	});
	return list;
};

/**
 * 设置px像素
 */
export const setPx = (val, defval = '') => {
	if (validatenull(val)) val = defval;
	if (validatenull(val)) return '';
	val = val + '';
	if (val.indexOf('%') === -1) {
		val = val + 'px';
	}
	return val;
};

/**
 * 字符串数据类型转化
 */
export const detailDataType = (value, type) => {
	if (validatenull(value)) return value;
	if (type === 'number') {
		return Number(value);
	} else if (type === 'string') {
		return value + '';
	} else {
		return value;
	}
};
// 获取url中的参数
export const getUrlParams = (url) => {
	let result = {
		url: '',
		params: {}
	};
	let list = url.split('?');
	result.url = list[0];
	let params = list[1];
	if (params) {
		let list = params.split('&');
		list.forEach((ele) => {
			let dic = ele.split('=');
			let label = dic[0];
			let value = dic[1];
			result.params[label] = value;
		});
	}
	return result;
};

/**
 * 数组的数据类型转化
 */
export const detailDic = (list = [], props = {}, type) => {
	let valueKey = props.value || PROPS_ENUM.value;
	let childrenKey = props.children || PROPS_ENUM.children;
	list.forEach((ele) => {
		ele[valueKey] = detailDataType(ele[valueKey], type);
		if (ele[childrenKey]) detailDic(ele[childrenKey], props, type);
	});
	return list;
};
/**
 * 根据字典的value显示label
 */

export const findByValue = (dic, value, props) => {
	// 如果为空直接返回
	if (validatenull(dic)) return value;
	let result = '';
	let isArray = value instanceof Array;
	let list = isArray ? value : [value];
	props = props || PROPS_ENUM;
	result = [];
	for (let i = 0; i < list.length; i++) {
		result.push(findLabelNode(dic, list[i], props) || list[i]);
	}
	if (isArray) {
		return result.join(ENUM_SHOW_SPLITOR).toString();
	}
	return result.join();
};

/**
 * 过滤字典翻译字段和空字段
 * @param {*} form
 * @param {*} translate
 * @returns
 */
export const filterDefaultParams = (form, translate = true) => {
	let data = deepClone(form);
	if (translate) return data;
	for (let o in data) {
		if (o.indexOf('$') !== -1 || validatenull(data[o])) {
			delete data[o];
		}
	}
	return data;
};
/**
 * 处理存在group分组的情况
 */
export const detailDicGroup = (dic = [], props = {}) => {
	let list = deepClone(dic);
	let groupsKey = props[PROPS_ENUM.groups] || PROPS_ENUM.groups;
	dic.forEach((ele) => {
		if (ele[groupsKey]) {
			list = list.concat(ele[groupsKey]);
		}
	});
	return list;
};
/**
 * 根据label去找到节点
 */
export const findLabelNode = (dic, value, props, obj) => {
	let result;
	if (!obj) dic = detailDicGroup(dic, props);
	let rev = (dic1) => {
		const labelKey = props.label || PROPS_ENUM.label;
		const valueKey = props.value || PROPS_ENUM.value;
		const childrenKey = props.children || PROPS_ENUM.children;
		for (let i = 0; i < dic1.length; i++) {
			const ele = dic1[i];
			const children = ele[childrenKey] || [];
			if (ele[valueKey] === value) {
				result = obj ? ele : ele[labelKey];
			} else {
				rev(children);
			}
		}
	};
	rev(dic);
	return result;
};
/**
 * 获取多层data
 */
export const getDeepData = (res) => {
	return (Array.isArray(res) ? res : res.data) || [];
};
export const getObjValue = (data, params = '', type) => {
	const list = params.split('.');
	let result = data;
	if (list[0] === '' && type !== 'object') {
		return getDeepData(data);
	} else if (list[0] !== '') {
		list.forEach((ele) => {
			result = result[ele];
		});
	}
	return result;
};

/**
 * 根据值查找对应的序号
 */
export const findArray = (dic, value, valueKey, obj) => {
	valueKey = valueKey || PROPS_ENUM.value;
	for (let i = 0; i < dic.length; i++) {
		if (dic[i][valueKey] === value) {
			return obj ? dic[i] : i;
		}
	}
	return -1;
};
/**
 * 根据位数获取*密码程度
 */
export const getPasswordChar = (result = '', char) => {
	let len = result.toString().length;
	result = '';
	for (let i = 0; i < len; i++) {
		result = result + char;
	}
	return result;
};

export const arraySort = (list = [], prop, callback) => {
	return list
		.filter((ele) => !validatenull(ele[prop]))
		.sort((a, b) => callback(a, b))
		.concat(list.filter((ele) => validatenull(ele[prop])));
};
export const clearVal = (obj, list = []) => {
	if (!obj) return {};
	Object.keys(obj).forEach((ele) => {
		if (list.includes(ele)) return;
		else if (ele.includes('$')) delete obj[ele];
		else if (!validatenull(obj[ele])) {
			let type = getObjType(obj[ele]);
			if (type === 'array') obj[ele] = [];
			else if (type === 'object') obj[ele] = {};
			else if (['number', 'boolean'].includes(type)) obj[ele] = undefined;
			else obj[ele] = '';
		}
	});
	return obj;
};
/**
 * 验证是否存在true/false
 */
export const vaildData = (val, dafult) => {
	if (typeof val === 'boolean') {
		return val;
	}
	return !validatenull(val) ? val : dafult;
};

export const uuid = () => {
	let s = [];
	let hexDigits = '0123456789abcdef';
	for (let i = 0; i < 36; i++) {
		s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
	}
	s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
	s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
	s[8] = s[13] = s[18] = s[23] = '-';

	let uuid = s.join('');
	return uuid;
};

/**
 * 解压
 * @param {*} zipStr64
 * @returns
 */
export const unzip = (zipStr64) => {
	// const unzipStr64 = Buffer.from(zipStr64, 'base64');
	// const unzipStr = pako.inflate(unzipStr64, { to: 'string' });
	// return unzipStr;
	const zipEncoded = atob(zipStr64); // 将 base64 字符串解码成二进制数据
	const zipContent = new Uint8Array(Array.from(zipEncoded, (c) => c.charCodeAt(0))); // 将二进制数据转换为 TypedArray
	const unzipContent = pako.inflate(zipContent, { to: 'string' }); // 解压缩二进制数据，得到字符串
	return unzipContent;
};

// 压缩
/**
 * @param {*} str
 * @returns
 */
export const zip = (str) => {
	const strEncoded = new TextEncoder().encode(str); // 将字符串编码为二进制数据
	const zipContent = pako.deflate(strEncoded); // 对二进制数据进行压缩
	const zipEncoded = btoa(String.fromCharCode.apply(null, zipContent)); // 将压缩后的二进制数据编码为 base64 字符串
	return zipEncoded;
};

// // let rafId = null
// export function setFrameTimeout(fn, delay = 5) {
//   let rafId = null
//   let stepCount = 0
//   function getFrameTimeout(time) {
//     if (stepCount < delay) {
//       stepCount += 1
//     } else {
//       fn && fn(rafId)
//       cancelAnimationFrame(rafId)
//     }
//     rafId = requestAnimationFrame(getFrameTimeout)
//   }
//   if (delay === 0) {
//     fn && fn(rafId)
//   } else {
//     getFrameTimeout()
//   }
//   return rafId
// }

// const t = Date.now()
function setFrameTimeout2(fn, delay = 30) {
	let startTime = Date.now();
	loop();
	function loop() {
		if (Date.now() - startTime >= delay) {
			fn();
			return;
		}
		requestAnimationFrame(loop);
	}
}

export class DelayTaskQueue {
	queue = [];

	// going = false

	defaultDelay = 1;

	delayOffset = 0;

	delayAtFirst = false;

	constructor(delay = 1, delayAtFirst = false) {
		this.defaultDelay = delay;
		this.delayAtFirst = delayAtFirst;
		this.delayOffset = 0;
	}

	go() {
		// if (this.going === true) {
		//   return
		// }
		while (this.queue.length !== 0) {
			// this.going === true
			const option = this.queue.shift();
			const task = (rafId) => {
				this.delayOffset -= option.delay;
				option.fn();
				cancelAnimationFrame(rafId);
			};

			if (this.queue.length === 0 && this.delayOffset === 0) {
				this.delayOffset += option.delay;
				setFrameTimeout2(() => {
					this.delayOffset -= option.delay;
				}, option.delay);
				// delayOffset === 0 代表队列里没有任务，触发判断 delayFirst 判断
				if (this.delayAtFirst === true) {
					this.delayOffset += option.delay;
					setFrameTimeout2(task, option.delay);
				} else {
					option.fn();
				}
			} else {
				setFrameTimeout2(task, this.delayOffset);
				this.delayOffset += option.delay;
			}
		}
		// this.going = false
		// this.delayOffset = 0
	}

	appendTask(fn, delay = null) {
		const fnDelay = typeof delay === 'number' ? delay : this.defaultDelay;
		const option = {
			fn,
			delay: fnDelay
		};
		this.queue.push(option);
		this.go();
	}
}

export const getSceneTreeFromBaseMap = async (baseMap, engineType) => {
	const sceneTree = {
		currentEngineType: '',
		currentEngine: '',
		twoDimEngine: '',
		twoDimSceneData: null,
		threeDimEngine: '',
		threeDimSceneData: null,
		bimEngine: '',
		bimSceneData: null,
		vizEngine: '',
		vizSceneData: null
	};
	let sceneData = {};
	let serviceIds = [];
	let serviceInfoData = {};

	sceneTree.currentEngineType = engineType;

	// 处理二维GIS引擎场景数据
	if (baseMap.twoDim) {
		sceneData = {
			sceneTo: '',
			sceneUrl: [],
			serviceInfo: [],
			container: 'engine-container',
			cameraParams: {},
			homeView: {},
			loadOptions: {}
		};
		switch (baseMap.twoDim) {
			case '超图':
				sceneData.sceneTo = 'SUPERMAP';
				sceneTree.twoDimEngine = 'SUPERMAP';
				sceneTree.currentEngine = 'SUPERMAP';
				break;
			case 'MAPBOX':
			case 'Mapbox':
				sceneData.sceneTo = 'MAPBOX';
				sceneTree.twoDimEngine = 'MAPBOX';
				sceneTree.currentEngine = 'MAPBOX';
				break;
			default:
				sceneData.sceneTo = baseMap.twoDim;
				sceneTree.twoDimEngine = baseMap.twoDim;
		}
		serviceIds = baseMap.twoDimServiceVos.map((x) => x.serviceId);
		serviceInfoData = await getServiceInfoByIds(serviceIds);
		sceneData.serviceInfo = serviceInfoData.data?.map((x) => {
			return {
				...x,
				stationUsername: pwdDecrypt(x.stationUsername),
				stationPassword: pwdDecrypt(x.stationPassword)
			};
		});
		sceneData.sceneUrl = sceneData.serviceInfo.map((x) => x.serviceUrl);
		sceneTree.twoDimSceneData = sceneData;
	}

	// 处理三维GIS引擎场景数据
	if (baseMap.threeDim) {
		sceneData = {
			sceneTo: '',
			sceneUrl: [],
			serviceInfo: [],
			container: 'engine-container',
			cameraParams: {},
			homeView: {},
			loadOptions: {}
		};
		switch (baseMap.threeDim) {
			case '超图':
				sceneData.sceneTo = 'SUPERMAP';
				sceneTree.threeDimEngine = 'SUPERMAP';
				sceneTree.currentEngine = 'SUPERMAP';
				break;
			default:
				sceneData.sceneTo = baseMap.threeDim;
				sceneTree.threeDimEngine = baseMap.threeDim;
		}
		serviceIds = baseMap.threeDimServiceVos.map((x) => x.serviceId);
		serviceInfoData = await getServiceInfoByIds(serviceIds);
		sceneData.serviceInfo = serviceInfoData.data?.map((x) => {
			return {
				...x,
				stationUsername: pwdDecrypt(x.stationUsername),
				stationPassword: pwdDecrypt(x.stationPassword)
			};
		});
		sceneData.sceneUrl = sceneData.serviceInfo.map((x) => x.serviceUrl);
		sceneTree.threeDimSceneData = sceneData;
	}

	// 处理BIM引擎场景数据
	if (baseMap.bim) {
		sceneData = {
			sceneTo: '',
			sceneUrl: [],
			serviceInfo: [],
			container: 'engine-container',
			cameraParams: {},
			homeView: {},
			loadOptions: {}
		};
		switch (baseMap.bim) {
			case 'BIMBASE':
			case 'BIMBase':
				sceneData.sceneTo = 'BIMBASE';
				sceneTree.bimEngine = 'BIMBASE';
				sceneTree.currentEngine = 'BIMBASE';
				break;
			default:
				sceneData.sceneTo = baseMap.bim;
				sceneTree.bimEngine = baseMap.bim;
		}
		serviceIds = [baseMap.bimServiceVos[0].serviceId];
		serviceInfoData = await getServiceInfoByIds(serviceIds);
		sceneData.serviceInfo = serviceInfoData.data?.map((x) => {
			return {
				...x,
				stationUsername: pwdDecrypt(x.stationUsername),
				stationPassword: pwdDecrypt(x.stationPassword)
			};
		})[0];
		sceneData.sceneUrl = sceneData.serviceInfo.serviceUrl;
		sceneTree.bimSceneData = sceneData;
	}

	// 处理VIZ引擎场景数据

	if (baseMap.viz) {
		sceneData = {
			sceneTo: '',
			sceneUrl: [],
			serviceInfo: [],
			container: 'engine-container',
			cameraParams: {},
			homeView: {},
			loadOptions: {}
		};
		switch (baseMap.viz) {
			case 'DTS':
				sceneData.sceneTo = 'DTS';
				sceneTree.vizEngine = 'DTS';
				sceneTree.currentEngine = 'DTS';
				break;
			default:
				sceneData.sceneTo = baseMap.viz;
				sceneTree.vizEngine = baseMap.viz;
		}
		serviceIds = [baseMap.vizServiceVos[0].serviceId];
		serviceInfoData = await getServiceInfoByIds(serviceIds);
		sceneData.serviceInfo = serviceInfoData.data?.map((x) => {
			return {
				...x,
				stationUsername: pwdDecrypt(x.stationUsername),
				stationPassword: pwdDecrypt(x.stationPassword)
			};
		})[0];
		sceneData.sceneUrl = sceneData.serviceInfo.serviceUrl;
		sceneTree.vizSceneData = sceneData;
	}

	return sceneTree;
};

export const getSceneDataByEngineType = (sceneTree, engineType) => {
	// const sceneTree = {
	// 	currentEngineType: '',
	// 	currentEngine: '',
	// 	twoDimEngine: '',
	// 	twoDimSceneData: null,
	// 	threeDimEngine: '',
	// 	threeDimSceneData: null,
	// 	bimEngine: '',
	// 	bimSceneData: null,
	// 	vizEngine: '',
	// 	vizSceneData: null
	// };
	switch (engineType) {
		case '二维GIS':
			return sceneTree.twoDimSceneData;
		case '三维GIS':
			return sceneTree.threeDimSceneData;
		case 'BIM':
			return sceneTree.bimSceneData;
		case 'VIZ':
			return sceneTree.vizSceneData;
		default:
			return null;
	}
};
